package com.yami.trading.huobi.data.websocket.utils;

import com.yami.trading.huobi.data.websocket.exception.SDKException;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

public class ConnectionFactory {

	private static Boolean LATENCY_DEBUG_SWATCH = Boolean.FALSE;

	private static LinkedBlockingQueue<NetworkLatency> LATENCY_DEBUG_QUEUE = new LinkedBlockingQueue<>();

	private static ConnectionPool connectionPool = new ConnectionPool(20, 300, TimeUnit.SECONDS);

	private static final OkHttpClient client = new OkHttpClient.Builder().followSslRedirects(false)
			.followRedirects(false).connectTimeout(5000, TimeUnit.MILLISECONDS).readTimeout(5000, TimeUnit.MILLISECONDS)
			.writeTimeout(5000, TimeUnit.MILLISECONDS).connectionPool(connectionPool)
			.addNetworkInterceptor(new Interceptor() {
				@NotNull
				@Override
				public Response intercept(@NotNull Chain chain) throws IOException {
					Request request = chain.request();

					Long startNano = System.nanoTime();

					Response response = chain.proceed(request);

					Long endNano = System.nanoTime();

					if (LATENCY_DEBUG_SWATCH) {
						LATENCY_DEBUG_QUEUE.add(new NetworkLatency(request.url().url().getPath(), startNano, endNano));
					}

					return response;
				}
			}).build();

	private static final Logger log = LoggerFactory.getLogger(ConnectionFactory.class);

	public static String execute(Request request) {

		Response response = null;
		String str = null;
		try {
			log.debug("[Request URL]{}", request.url());
			response = client.newCall(request).execute();
			if (response.code() != 200) {
				throw new SDKException(SDKException.EXEC_ERROR,
						"[Execute] Response Status Error : " + response.code() + " message:" + response.message());
			}
			if (response != null && response.body() != null) {
				str = response.body().string();
				response.close();
			} else {
				throw new SDKException(SDKException.ENV_ERROR, "[Execute] Cannot get the response from server");
			}
			log.debug("[Response]{}", str);
			return str;
		} catch (IOException e) {
			e.printStackTrace();
			throw new SDKException(SDKException.RUNTIME_ERROR, "[Execute] Cannot get the response from server");
		}

	}

	public static WebSocket createWebSocket(Request request, WebSocketListener listener) {
		return client.newWebSocket(request, listener);
	}

	public static void setLatencyDebug() {
		LATENCY_DEBUG_SWATCH = Boolean.TRUE;
	}

	public static LinkedBlockingQueue<NetworkLatency> getLatencyDebugQueue() {
		return LATENCY_DEBUG_QUEUE;
	}

	public static void clearLatencyDebugQueue() {
		LATENCY_DEBUG_QUEUE.clear();
	}

	public static class NetworkLatency {

		private String path;

		private Long startNanoTime;

		private Long endNanoTime;

		public NetworkLatency(String path, Long startNanoTime, Long endNanoTime) {
			this.path = path;
			this.startNanoTime = startNanoTime;
			this.endNanoTime = endNanoTime;
		}

		public String getPath() {
			return path;
		}

		public void setPath(String path) {
			this.path = path;
		}

		public Long getStartNanoTime() {
			return startNanoTime;
		}

		public void setStartNanoTime(Long startNanoTime) {
			this.startNanoTime = startNanoTime;
		}

		public Long getEndNanoTime() {
			return endNanoTime;
		}

		public void setEndNanoTime(Long endNanoTime) {
			this.endNanoTime = endNanoTime;
		}

	}
}
